package concurrency.chapter5;

import java.util.concurrent.TimeUnit;

/**
 * @author honway.liu
 * @date 2019-06-06 18:42
 * @email gm100861@gmail.com
 * @blog http://linuxsogood.org
 *
 * 生产者消费者
 * 使用Object 的wait()和notify()来做线程间通讯, 如果多个生产者消费者,该方法就不能用了
 * 因为notify()只会唤醒一个线程,如果有2个生产者和2个消费者,假设消费者都已经处于wait的情况下,生产者唤醒了生产者,就会出问题了
 * 可以使用notifyAll() 来解决这个问题. notifyAll() 会唤醒使用该锁的所有的其它在等待的线程.
 * wait() 和 notify()定义在Object类上,还是有道理的,我们可以使用任意对象来做锁,如果定义在Thread上就有点不合适了.
 */
public class ProducerConsumerVersion2 {

    private int resource = 0;
    private static final int MAX = 500;

    private static final byte[] LOCK = new byte[0];
    private static final byte[] LOCK2 = new byte[0];

    private volatile boolean isProduced = false;

    public void producer() {
        synchronized (LOCK) {
            while (resource < MAX) {
                if (isProduced) {
                    try {
                        LOCK.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    System.out.println(Thread.currentThread().getName() + "->" + (++resource));
                    isProduced = true;
                    LOCK.notifyAll();
                }
            }
        }
    }

    public void consumer() {
        while (resource <= MAX) {
            synchronized (LOCK) {
                if (isProduced) {
                    System.out.println(Thread.currentThread().getName() + "->" + resource);
                    isProduced = false;
                    LOCK.notifyAll();
                } else {
                    try {
                        LOCK.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public void method() {
        synchronized (LOCK2) {
            try {
                LOCK2.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("被唤醒了???");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ProducerConsumerVersion2 producerConsumerVersion2 = new ProducerConsumerVersion2();
        new Thread(producerConsumerVersion2::producer, "P1").start();
        new Thread(producerConsumerVersion2::producer, "P2").start();

        new Thread(producerConsumerVersion2::consumer, "C1").start();
        new Thread(producerConsumerVersion2::consumer, "C2").start();


        new Thread(producerConsumerVersion2::method, "TEST").start();

        TimeUnit.SECONDS.sleep(2);
        LOCK2.notify();
    }
}
